package com.xinqi.modules.prepare.video.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xinqi.common.base.dto.CommonFileDTO;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.common.base.response.PageInfo;
import com.xinqi.common.base.response.Param;
import com.xinqi.common.base.utils.json.JSON;
import com.xinqi.common.mybatis.utils.Pages;
import com.xinqi.common.mybatis.utils.Queries;
import com.xinqi.common.security.utils.UserHelp;
import com.xinqi.modules.prepare.common.dto.data.PrepareVideoData;
import com.xinqi.modules.prepare.common.service.PrepareAuthService;
import com.xinqi.modules.prepare.folder.manager.PrepareFileFolderManager;
import com.xinqi.modules.prepare.prepare.enums.PrepareMemberPermissionEnum;
import com.xinqi.modules.prepare.prepare.enums.PrepareOperateLogEnum;
import com.xinqi.modules.prepare.prepare.manager.PrepareOperateLogManager;
import com.xinqi.modules.prepare.video.convert.PrepareVideoConvert;
import com.xinqi.modules.prepare.video.domain.PrepareVideoEntity;
import com.xinqi.modules.prepare.video.dto.req.PrepareVideoCreateDTO;
import com.xinqi.modules.prepare.video.dto.req.PrepareVideoDeleteDTO;
import com.xinqi.modules.prepare.video.dto.req.PrepareVideoPointQueryDTO;
import com.xinqi.modules.prepare.video.dto.req.PrepareVideoQueryDTO;
import com.xinqi.modules.prepare.video.dto.req.PrepareVideoUpdateDTO;
import com.xinqi.modules.prepare.video.dto.rsp.PrepareVideoResultDTO;
import com.xinqi.modules.prepare.video.manager.PrepareVideoManager;
import com.xinqi.modules.prepare.video.service.PrepareVideoPointService;
import com.xinqi.modules.prepare.video.service.PrepareVideoService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.validation.Valid;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 备课区互动视频服务层实现
 *
 * @author: system
 * @date: 2023/03/19
 */
@Validated
@Service("prepareVideoService")
@RequiredArgsConstructor
public class PrepareVideoServiceImpl implements PrepareVideoService {
    private final PrepareVideoConvert prepareVideoConvert;
    private final PrepareVideoManager prepareVideoManager;
    private final PrepareAuthService prepareAuthService;
    private final PrepareFileFolderManager prepareFileFolderManager;
    private final PrepareVideoPointService prepareVideoPointService;
    private final PrepareOperateLogManager prepareOperateLogManager;

    /**
     * 分页查询 备课区互动视频数据
     */
    @Override
    @DS("slaver")
    public PageInfo<PrepareVideoResultDTO> page(Param pageable, PrepareVideoQueryDTO query) {
        IPage<PrepareVideoEntity> page = prepareVideoManager.page(Pages.page(pageable), wrapper(query));
        return Pages.convert(page, prepareVideoConvert::convert);
    }

    /**
     * 查询 备课区互动视频数据
     */
    @Override
    public List<PrepareVideoResultDTO> find(PrepareVideoQueryDTO query) {
        return prepareVideoManager.list(wrapper(query)).stream()
            .map(prepareVideoConvert::convert).collect(Collectors.toList());
    }

    private LambdaQueryWrapper<PrepareVideoEntity> wrapper(PrepareVideoQueryDTO query) {
        LambdaQueryWrapper<PrepareVideoEntity> wrapper = Queries.lambda();
        Queries.accept(query.getId(), v -> wrapper.eq(PrepareVideoEntity::getId, v));
        return wrapper;
    }

    /**
     * 根据id查询 备课区互动视频数据
     */
    @Override
    public PrepareVideoResultDTO findById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        PrepareVideoResultDTO prepareVideoResultDTO = Optional.ofNullable(prepareVideoManager.findById(id)).map(prepareVideoConvert::convert).orElse(null);
        if (prepareVideoResultDTO == null) {
            return null;
        }
        PrepareVideoPointQueryDTO dto = new PrepareVideoPointQueryDTO();
        dto.setVideoId(id);
        prepareVideoResultDTO.setPointList(prepareVideoPointService.find(dto));
        return prepareVideoResultDTO;
    }

    @Override
    public PrepareVideoData find(Long id) {
        return prepareVideoConvert.convert(findById(id));
    }

    /**
     * 新增 备课区互动视频数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long insert(@Valid PrepareVideoCreateDTO dto) {
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isNotEmpty(dto.getFiles()), "视频不能为空");

        prepareAuthService.check(dto.getPrepareId(), PrepareMemberPermissionEnum.新建);
        PrepareVideoEntity entity = prepareVideoConvert.create(dto);
        entity.setUserId(UserHelp.userId());
        prepareVideoManager.save(entity);
        prepareOperateLogManager.addFileOperateLog(entity, PrepareOperateLogEnum.FILE_ADD);
        // 创建备课区文件
        prepareFileFolderManager.insertFile(entity, entity.getPrepareId(), dto.getFolderId(), dto.getIsAutoGenerateName());
        return entity.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long insert(@Valid PrepareVideoData data) {
        PrepareVideoCreateDTO dto = prepareVideoConvert.create(data);
        dto.setPointNum(Optional.ofNullable(data.getPointList()).map(List::size).orElse(0));
        Long videoId = insert(dto);
        if (CollectionUtils.isNotEmpty(data.getPointList())) {
            prepareVideoPointService.insert(data.getPrepareId(), videoId, data.getPointList());
        }
        return videoId;
    }

    /**
     * 根据id修改 备课区互动视频数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateById(@Valid PrepareVideoUpdateDTO dto) {
        CommonErrors.BAD_REQUEST.check(CollectionUtils.isNotEmpty(dto.getFiles()), "视频不能为空");

        PrepareVideoEntity old = Optional.ofNullable(prepareVideoManager.getById(dto.getId()))
            .orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("数据不存在"));
        prepareAuthService.check(old.getPrepareId(), PrepareMemberPermissionEnum.编辑);
        PrepareVideoEntity entity = prepareVideoConvert.update(dto);
        boolean b = prepareVideoManager.updateById(entity);
        if (b) {
            // 更新备课区文件
            PrepareVideoEntity newEntity = prepareVideoManager.getById(dto.getId());
            prepareFileFolderManager.updateFile(newEntity, newEntity.getPrepareId());
            prepareOperateLogManager.addFileOperateLog(newEntity, PrepareOperateLogEnum.FILE_EDIT);
        }
        List<CommonFileDTO> oldFiles = JSON.parseList(old.getFiles(), CommonFileDTO.class);
        //url有变动时，删除环节
        if (isDeleteVideoPoint(dto.getFiles(), oldFiles)) {
            prepareVideoPointService.deleteByVideoId(entity.getId());
        }
        return b;
    }

    private boolean isDeleteVideoPoint(List<CommonFileDTO> newFileList, List<CommonFileDTO> oldFileList) {
        if (CollectionUtils.isEmpty(oldFileList)) {
            return false;
        }
        CommonFileDTO oldFile = oldFileList.get(0);
        if (oldFile.getFileUrl() == null) {
            return false;
        }
        if (CollectionUtils.isEmpty(newFileList)) {
            return true;
        }
        CommonFileDTO newFile = newFileList.get(0);
        return !Objects.equals(newFile.getFileUrl(), oldFile.getFileUrl());
    }

    /**
     * 根据id删除 备课区互动视频数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        PrepareVideoEntity entity = Optional.ofNullable(prepareVideoManager.getById(id))
            .orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("数据不存在"));
        prepareAuthService.check(entity.getPrepareId(), PrepareMemberPermissionEnum.删除);
        boolean b = prepareVideoManager.deleteById(entity);
        if (b) {
            // 删除备课区文件
            prepareFileFolderManager.deleteFile(entity, entity.getPrepareId());
        }

        // 删除切片，不能删除切片，因为切片为物理删除，删除后无法恢复
//        prepareVideoPointManager.deleteByVideoId(id);
        return b;
    }

    /**
     * 根据id删除 备课区互动视频数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(PrepareVideoDeleteDTO dto) {
        return deleteById(dto.getId());
    }
}
